﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Globalization;
using System.Windows.Forms;
using System.Net;
using System.IO;
using Microsoft.Xna.Framework.Graphics;

namespace FontManager
{
    public static class Helper
    {
        #region Bitmap\Image handlers (resize, crop)
        /// <summary>
        /// takes a uri of the image and resizes it to fit as thumbnail;
        /// </summary>
        /// <param _name="file">image uri</param>
        /// <param _name="width">expected width</param>
        /// <param _name="height">expected height</param>
        /// <param _name="onlyResizeIfWider"></param>
        /// <returns>resized image</returns>
        public static Image ResizeImage(string file, int width, int height, bool onlyResizeIfWider)
        {
            using (Image image = Image.FromFile(file))
            {
                // Prevent using images internal thumbnail
                image.RotateFlip(RotateFlipType.Rotate180FlipNone);
                image.RotateFlip(RotateFlipType.Rotate180FlipNone);

                if (onlyResizeIfWider == true)
                {
                    if (image.Width <= width)
                    {
                        width = image.Width;
                    }
                }

                int newHeight = image.Height * width / image.Width;
                if (newHeight > height)
                {
                    // Resize with height instead
                    width = image.Width * height / image.Height;
                    newHeight = height;
                }

                //second entry is a thumbnail
                Image newImage = image.GetThumbnailImage(width, newHeight, null, IntPtr.Zero);

                image.Dispose();
                return newImage;
            }
        }
        /// <summary>
        /// takes an image and resizes it to fit as thumbnail;
        /// </summary>
        /// <param _name="file">image</param>
        /// <param _name="width">expected width</param>
        /// <param _name="height">expected height</param>
        /// <param _name="onlyResizeIfWider"></param>
        /// <returns>resized image</returns>
        public static Image ResizeImage(Image img, int width, int height, bool onlyResizeIfWider)
        {
            using (Image image = img)
            {
                // Prevent using images internal thumbnail
                image.RotateFlip(RotateFlipType.Rotate180FlipNone);
                image.RotateFlip(RotateFlipType.Rotate180FlipNone);

                if (onlyResizeIfWider == true)
                {
                    if (image.Width <= width)
                    {
                        width = image.Width;
                    }
                }

                int newHeight = image.Height * width / image.Width;
                if (newHeight > height)
                {
                    // Resize with height instead
                    width = image.Width * height / image.Height;
                    newHeight = height;
                }

                //second entry is a thumbnail
                Image newImage = image.GetThumbnailImage(width, newHeight, null, IntPtr.Zero);

                image.Dispose();
                return newImage;
            }
        }
        /// <summary>
        /// loading _image;
        /// keeping the count of empty lines at the top and at the bottom;
        /// once know lines number, 
        /// create a rectangle;
        /// create new image using rectangle;
        /// returning new croped image;
        /// </summary>
        /// <param _name="file"></param>
        /// <returns></returns>
        public static Image cropImage(string file)
        {
            Bitmap img = new Bitmap(file);

            //*BELOW CODE HANDLES CROPING ONLY OF ROWS NOT COLUMNS!!!!!!!!!!
            //iterates through the images and retrieves empty rows
            int topEmptyRows = 0;
            int imgHeight = 0;

            for (int y = 0; y < img.Height; y++)
            {
                int transpPixels = 0;
                int filledPixels = 0;
                for (int x = 0; x < img.Width; x++)
                {
                    Color c = img.GetPixel(x, y);
                    if (c.A == 0) //transparent LineColor
                        transpPixels++;
                    else
                        filledPixels++;

                    if (transpPixels + filledPixels == img.Width)
                    {
                        if (imgHeight == 0 && transpPixels == img.Width)
                        {
                            topEmptyRows++;
                        }
                        if (filledPixels != 0)
                        {
                            imgHeight++;
                        }
                    }
                }
            }
            Rectangle cropRect = new Rectangle(0, topEmptyRows, img.Width, imgHeight);
            Bitmap newImg = new Bitmap(cropRect.Width, cropRect.Height);

            Graphics gfx = Graphics.FromImage(newImg);
            gfx.DrawImage(img, 0, 0, cropRect, GraphicsUnit.Pixel);
            img.Dispose();
            return newImg;
        }

        /// <summary>
        /// returns an image after a specific scale was applied
        /// </summary>
        /// <param _name="origin">original image</param>
        /// <param _name="Scale">scale</param>
        /// <returns></returns>
        public static Bitmap getScaledImg(Image origin, float Scale)
        {
            try
            {
                Bitmap newImg = new Bitmap((int)(origin.Width * Scale), (int)(origin.Height * Scale));

                using (Graphics gfx = Graphics.FromImage(newImg))
                {
                    gfx.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
                    gfx.DrawImage(origin, new Rectangle(0, 0, newImg.Width, newImg.Height));
                    gfx.Dispose();
                }

                return newImg;
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                return null;
            }
        }
        #endregion

        #region sorting
        /// <summary>
        /// Lists sort method
        /// </summary>
        /// <param _name="unsortedList">list of strings</param>
        public static void sortListByHex(List<string> unsortedList)
        {
            unsortedList.Sort(delegate(string c1, string c2) { return c1.CompareTo(c2); });
        }
        /// <summary>
        /// Lists sort method
        /// </summary>
        /// <param _name="unsortedList">list of FontCharacter objects</param>
        public static void sortCharacterList(List<FontCharacter> unsortedList)
        {
            unsortedList.Sort(delegate(FontCharacter c1, FontCharacter c2) { return c1.Name.CompareTo(c2.Name); });
        }
        #endregion

        #region character handlers
        /// <summary>
        /// changes character value to character
        /// </summary>
        /// <param _name="character">character value</param>
        /// <returns>character of given character value</returns>
        public static char HEXtoCHAR(string hex)
        {
            hex = hex.Substring(2); // To remove leading 0x
            int num = int.Parse(hex, NumberStyles.AllowHexSpecifier);
            char cnum = (char)num;

            return cnum;
        }

        /// <summary>
        /// takes character value and based on it draws an image of given parameters
        /// </summary>
        /// <param _name="character">character character</param>
        /// <param _name="width">image width</param>
        /// <param _name="height">image height</param>
        /// <returns>image of given char</returns>
        public static Image drawImageFromChar(char character, int width, int height)
        {
            Image img = new Bitmap(width, height);
            using (Graphics gfx = Graphics.FromImage(img))
            {
                GraphicsUnit gfu = GraphicsUnit.Pixel;
                gfx.FillRectangle(new SolidBrush(Color.Black), img.GetBounds(ref gfu));
                gfx.DrawString(character.ToString(), new Font("Arial", 12), new SolidBrush(Color.White), Point.Empty);
            }
            return img;
        }

        /// <summary>
        /// translates given string to a list of characters
        /// </summary>
        /// <param _name="s">string (text)</param>
        /// <returns>list of given string characters</returns>
        public static List<string> stringToHex(string s)
        {
            List<string> Hexs = new List<string>();
            string Characters = s;

            foreach (char i in Characters)
            {
                char c = i;
                int unicode = c;
                Hexs.Add(string.Format("0x{0:x4}", unicode));
            }
            return Hexs;
        }

        /// <summary>
        /// character to character conversion
        /// </summary>
        /// <param _name="s">character</param>
        /// <returns>character value</returns>
        public static string charToHex(char s)
        {
            char c = s;
            int unicode = c;
            return string.Format("0x{0:x4}", unicode);
        }
        #endregion

        #region get image width and scale
        /// <summary>
        /// What it does it takes datagridview size and number of images a.k.a. cells
        /// and based on that calculates how big the cell should be to fill the hole space;
        /// </summary>
        /// <param _name="numberOfImages">total number of images</param>
        /// <param _name="width">grid width</param>
        /// <param _name="height">grid height</param
        /// <returns>the width of the cell to fit into given parameters</returns>
        public static int getImgWidth(int numberOfImages, int width, int height)
        {
            int imgWidth = 0;
            double totalArea = width * height;
            double cellArea = totalArea / numberOfImages;
            imgWidth = (int)Math.Sqrt(cellArea);
            return imgWidth;
        }

        /// <summary>
        /// check the list of characters and returns the biggest(widest) one which shall be used
        /// as an default one for data grid view.
        /// </summary>
        /// <param _name="chars">FontCharacter objects list</param>
        /// <returns>the widest character</returns>
        public static int getDefaultWidth(List<FontCharacter> chars)
        {
            int width = 0;
            foreach (FontCharacter c in chars)
            {
                if (c.Height > width)
                    width = (int)c.Height;
            }
            return width;
        }

        /// <summary>
        /// gets the scale of given values
        /// </summary>
        /// <param _name="origin">original size</param>
        /// <param _name="newsize">expected size</param>
        /// <returns></returns>
        public static int getScale(int origin, int newsize)
        {
            int scale = 1;
            scale = (newsize * 100) / origin;
            return scale;
        }
        #endregion

        #region inputBox
        /// <summary>
        /// Input dialog box used to get some specific input.
        /// </summary>
        /// <param _name="title">input box title</param>
        /// <param _name="promptText">the text which will be writen in the dialog</param>
        /// <param _name="defaultText">default text of textBox</param>
        /// <param _name="value">result</param>
        /// <returns>dialog window</returns>
        public static DialogResult InputBox(string title, string promptText,string defaultText, ref string value)
        {
            Form form = new Form();
            Label label = new Label();
            TextBox textBox = new TextBox();
            Button buttonOk = new Button();
            Button buttonCancel = new Button();

            form.Text = title;
            label.Text = promptText;
            textBox.Text = defaultText;

            buttonOk.Text = "OK";
            buttonCancel.Text = "Cancel";
            buttonOk.DialogResult = DialogResult.OK;
            buttonCancel.DialogResult = DialogResult.Cancel;

            label.SetBounds(9, 20, 372, 13);
            textBox.SetBounds(12, 36, 372, 20);
            buttonOk.SetBounds(228, 72, 75, 23);
            buttonCancel.SetBounds(309, 72, 75, 23);

            label.AutoSize = true;
            textBox.Anchor = textBox.Anchor | AnchorStyles.Right;
            buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
            buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;

            form.ClientSize = new Size(396, 107);
            form.Controls.AddRange(new Control[] { label, textBox, buttonOk, buttonCancel });
            form.ClientSize = new Size(Math.Max(300, label.Right + 10), form.ClientSize.Height);
            form.FormBorderStyle = FormBorderStyle.FixedDialog;
            form.StartPosition = FormStartPosition.CenterScreen;
            form.MinimizeBox = false;
            form.MaximizeBox = false;
            form.AcceptButton = buttonOk;
            form.CancelButton = buttonCancel;

            DialogResult dialogResult = form.ShowDialog();
            value = textBox.Text;
            return dialogResult;
        }

        /// <summary>
        /// messagebox dialog result window.
        /// </summary>
        /// <param _name="title">title</param>
        /// <param _name="message">the message writen in the middle of this dialog</param>
        /// <returns>created dialog</returns>
        public static DialogResult infoBox(string title, string message)
        {
            DialogResult ds = MessageBox.Show(title, message, MessageBoxButtons.YesNo);
            return ds;
        }

        #endregion

        /// <summary>
        /// Checking methods to know what kind of character it is.
        /// Is used when filtering.
        /// </summary>
        #region character type
        public enum characterType
        {
            NUMBERS,
            LETTERS_UPPERCASE,
            LETTERS_LOWERCASE,
            LETTERS_SPECIAL,
            SYMBOLS,
            NONE
        }

        public static characterType getCharacterType(string charHex)
        {
            if (isNumber(HEXtoCHAR(charHex)))
                return characterType.NUMBERS;
            if (isUppercase(HEXtoCHAR(charHex)))
                return characterType.LETTERS_UPPERCASE;
            if (isLowercase(HEXtoCHAR(charHex)))
                return characterType.LETTERS_LOWERCASE;
            if (isSpecial(HEXtoCHAR(charHex)))
                return characterType.LETTERS_SPECIAL;
            if (isSymbol(HEXtoCHAR(charHex)))
                return characterType.SYMBOLS;

            return characterType.NONE;
        }

        private static bool isNumber(char character)
        {
            if (FontSplitter.NUMBERS.Contains(character))
                return true;
            else
                return false;
        }
        private static bool isUppercase(char character)
        {
            if (FontSplitter.LETTERS_UPPERCASE.Contains(character))
                return true;
            else
                return false;
        }
        private static bool isLowercase(char character)
        {
            if (FontSplitter.LETTERS_LOWERCASE.Contains(character))
                return true;
            else
                return false;
        }
        private static bool isSpecial(char character)
        {
            if (FontSplitter.LETTERS_SPECIAL.Contains(character))
                return true;
            else
                return false;
        }
        private static bool isSymbol(char character)
        {
            if (FontSplitter.SYMBOLS.Contains(character))
                return true;
            else
                return false;
        }
        #endregion

        /// <summary>
        /// takes directory and font object and compares them with the characters list it contains.
        /// </summary>
        /// <param _name="dir">images directory</param>
        /// <param _name="font">font object</param>
        /// <returns>return differences between directory and font.character list</returns>
        public static List<string> compareFolderWithXML(string dir, FontFont font)
        {
            List<string> differences = new List<string>();

            List<string> dirHEX = new List<string>();
            foreach (string link in Directory.GetFiles(dir))
            {
                if (isLinkHexPng(link))
                    dirHEX.Add(Path.GetFileNameWithoutExtension(link));
            }

            List<string> fontHEX = new List<string>();
            foreach (FontCharacter c in font.Characters)
                fontHEX.Add(c.Name);

            foreach (string s in dirHEX)
            {
                if (!fontHEX.Contains(s))
                    differences.Add(s);
            }
            Console.WriteLine(differences.Count);

            return differences;
        }

       /// <summary>
       /// Checks is given link is:
       /// "*.png" extension;
       /// starts with "0x";
       /// _name's length not more than 7;
       /// </summary>
       /// <param _name="link">image link</param>
       /// <returns>is link character value result</returns>
        public static bool isLinkHexPng(string link)
        {
            return Path.GetExtension(link) == ".png" && Path.GetFileNameWithoutExtension(link).StartsWith("0x") && Path.GetFileNameWithoutExtension(link).Length <= 7;
        }

        /// <summary>
        /// Method which takes texture2d and changes it into Image file.
        /// Is used when leading buttons images to a content in XNA and then using them
        /// in winForms as an backImage.
        /// </summary>
        /// <param _name="texture"></param>
        /// <returns></returns>
        public static System.Drawing.Image Texture2Image(Texture2D texture)
        {
            //Memory stream to store the bitmap data.
            MemoryStream ms = new MemoryStream();

            //Save the texture to the stream.
            texture.SaveAsPng(ms, texture.Width, texture.Height);

            //Seek the beginning of the stream.
            ms.Seek(0, SeekOrigin.Begin);

            //Create an image from a stream.
            System.Drawing.Image bmp2 = System.Drawing.Bitmap.FromStream(ms);

            //Close the stream, we nolonger need it.
            ms.Close();
            ms = null;
            return bmp2;
        }
    }
}
